<template>
    <div class="simple-table">
        <div class="header" v-if="filters.length || buttons.length">
            <div class="header-form" v-for="filter in filters" :key="filter.prop">
                <span v-if="filter.label">{{ filter.label }}：</span>
                <el-input v-if="filter.type === 'input'" class="el_input" v-model="form[filter.prop]"
                    :placeholder="filter.placeholder || '请输入'" :clearable="filter.clearable !== false"
                    @keyup.enter.native="handleEnter(filter)" />
                <el-select v-else-if="filter.type === 'select'" v-model="form[filter.prop]"
                    :placeholder="filter.placeholder || '请选择'" :clearable="filter.clearable !== false">
                    <el-option v-for="option in filter.options || []" :key="option.value" :label="option.label"
                        :value="option.value" />
                </el-select>
                <slot v-else :name="filter.slot" :filter="filter" />
            </div>
            <div class="header-buttons" v-if="buttons.length">
                <div v-for="button in buttons" :key="button.action || button.label"
                    :class="[getButtonClass(button), { 'is-disabled': button.disabled }]"
                    @click="handleButtonClick(button)">
                    {{ button.label }}
                </div>
            </div>
        </div>

        <div class="content">
            <el-table :data="data" v-loading="loading" border v-bind="tableProps || {}">
                <template v-for="column in columns">
                    <el-table-column v-if="column.type === 'index'" :key="column.prop || column.label || 'index-column'"
                        type="index" :index="column.indexMethod || indexMethod" :label="column.label || '序号'"
                        :width="column.width" :align="column.align || 'center'" />
                    <el-table-column v-if="column.prop === 'status'"
                        :key="column.prop || column.label || 'index-column'" type="index"
                        :index="column.indexMethod || indexMethod" :label="column.label" :width="column.width"
                        :align="column.align || 'center'">
                        <template slot-scope="scope">
                            {{ scope.row.status === 'normal' ? '正常' : scope.row.status === 'exception' ? '异常' :
                                scope.row.status === 'rectified' ? '已整改' : '--' }}
                        </template>
                    </el-table-column>
                    <el-table-column v-else :key="column.prop || column.label" :prop="column.prop" :label="column.label"
                        :width="column.width" :min-width="column.minWidth" :fixed="column.fixed"
                        :align="column.align || 'center'" :show-overflow-tooltip="column.showOverflowTooltip">
                        <template slot-scope="scope">
                            <slot v-if="column.slot" :name="column.slot" :row="scope.row" :column="column"
                                :index="scope.$index" />
                            <template v-else-if="column.type === 'action'">
                                <el-button v-for="action in column.actions || []" :key="action.action || action.label"
                                    type="text" size="mini" @click="handleActionClick(action, scope.row)"
                                    :disabled="action.disabled">
                                    {{ action.label }}
                                </el-button>
                            </template>
                            <span v-else>{{ getCellValue(scope.row, column, scope.$index) }}</span>
                        </template>
                    </el-table-column>
                </template>
            </el-table>
            <div class="page" v-if="pagination">
                <el-pagination @size-change="handleSizeChange" :current-page="pagination.pageNo"
                    @current-change="handleCurrentChange" :page-sizes="pagination.pageSizes || [5, 10, 20, 50]"
                    :page-size="pagination.pageSize" layout="sizes, prev, pager, next" :total="pagination.total || 0" />
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "SimpleTable",
    props: {
        filters: {
            type: Array,
            default: () => []
        },
        form: {
            type: Object,
            default: () => ({})
        },
        buttons: {
            type: Array,
            default: () => []
        },
        columns: {
            type: Array,
            default: () => []
        },
        data: {
            type: Array,
            default: () => []
        },
        loading: {
            type: Boolean,
            default: false
        },
        pagination: {
            type: Object,
            default: () => ({
                pageNo: 1,
                pageSize: 10,
                total: 0
            })
        },
        tableProps: {
            type: Object,
            default: () => ({})
        },
        exportConfig: {
            type: Object,
            default: () => ({})
        },
        importConfig: {
            type: Object,
            default: () => ({})
        }
    },
    data() {
        return {
            exporting: false,
            importing: false,
            importInputEl: null
        }
    },
    methods: {
        getButtonClass(button) {
            if (button.className) return button.className
            if (button.type === 'primary' || button.type === 'main') return 'blue_btn'
            return 'default_btn'
        },
        handleButtonClick(button) {
            if (button.disabled) return
            const actionKey = (button.action || '').toString().toLowerCase()
            const labelKey = (button.label || '').toString().toLowerCase()
            if (actionKey === 'export' || labelKey === '导出') {
                this.handleExport()
                return
            }
            if (actionKey === 'import' || labelKey === '导入') {
                this.handleImport()
                return
            }
            this.$emit('button-click', button)
        },
        handleActionClick(action, row) {
            if (action.disabled) return
            this.$emit('row-action', {
                action: action.action || action.name,
                row
            })
        },
        handleSizeChange(size) {
            this.$emit('size-change', size)
        },
        handleCurrentChange(page) {
            this.$emit('page-change', page)
        },
        indexMethod(index) {
            const pageNo = Number(this.pagination.pageNo) || 1
            const pageSize = Number(this.pagination.pageSize) || 10
            return (pageNo - 1) * pageSize + index + 1
        },
        handleEnter(filter) {
            this.$emit('filter-enter', filter)
        },
        getCellValue(row, column, index) {
            if (typeof column.formatter === 'function') {
                return column.formatter(row, column, index)
            }
            if (!column.prop) return ''
            const value = row[column.prop]
            return value !== undefined && value !== null && value !== '' ? value : column.emptyText || '--'
        },
        async handleExport() {
            if (this.exporting) {
                if (this.$message) {
                    this.$message.warning('正在导出中，请稍候…')
                }
                return
            }
            const config = this.getExportConfig()
            if (!config) {
                if (this.$message) {
                    this.$message.warning('当前未配置导出功能')
                }
                return
            }
            this.exporting = true
            this.$emit('export-start')
            try {
                let sourceData
                if (typeof config.request === 'function') {
                    sourceData = await config.request({
                        filters: { ...this.form },
                        pagination: { ...this.pagination },
                        columns: this.columns
                    })
                } else if (typeof config.getData === 'function') {
                    sourceData = await Promise.resolve(config.getData({
                        filters: { ...this.form },
                        pagination: { ...this.pagination },
                        columns: this.columns
                    }))
                } else if (Array.isArray(config.data)) {
                    sourceData = config.data
                } else {
                    sourceData = this.data
                }

                if (sourceData instanceof Blob) {
                    this.createBlobAndDownload(sourceData, config.filename || this.resolveExportFilename())
                    config.onSuccess && config.onSuccess({ blob: sourceData, from: 'api' })
                    this.$emit('export-success', { blob: sourceData, from: 'api' })
                    if (this.$message) {
                        this.$message.success('导出成功')
                    }
                    return
                }

                if (!Array.isArray(sourceData) || sourceData.length === 0) {
                    if (this.$message) {
                        this.$message.warning('暂无可导出的数据')
                    }
                    config.onEmpty && config.onEmpty()
                    this.$emit('export-empty')
                    return
                }

                const rows = typeof config.transform === 'function'
                    ? config.transform(sourceData, this.columns)
                    : this.resolveExportDataset(sourceData)

                if (!Array.isArray(rows) || rows.length === 0) {
                    if (this.$message) {
                        this.$message.warning('导出数据格式不正确')
                    }
                    this.$emit('export-error', new Error('Invalid export rows'))
                    return
                }

                const filename = config.filename || this.resolveExportFilename()
                this.downloadCsv(rows, filename)
                config.onSuccess && config.onSuccess({ rows, from: config.request ? 'api' : 'virtual' })
                this.$emit('export-success', { rows, from: config.request ? 'api' : 'virtual' })
                if (this.$message) {
                    this.$message.success('导出成功')
                }
            } catch (error) {
                console.error('SimpleTable 导出失败：', error)
                if (config && typeof config.onError === 'function') {
                    config.onError(error)
                }
                this.$emit('export-error', error)
                if (this.$message) {
                    this.$message.error('导出失败，请稍后重试')
                }
            } finally {
                this.exporting = false
                this.$emit('export-finish')
            }
        },
        handleImport() {
            if (this.importing) {
                if (this.$message) {
                    this.$message.warning('正在导入中，请稍候…')
                }
                return
            }
            const config = this.getImportConfig()
            if (!config) {
                if (this.$message) {
                    this.$message.warning('当前未配置导入功能')
                }
                return
            }
            this.ensureFileInput()
            if (this.importInputEl) {
                this.importInputEl.accept = config.accept || '.csv,.xlsx,.xls,.json'
                this.importInputEl.click()
            }
        },
        ensureFileInput() {
            if (this.importInputEl) return
            const input = document.createElement('input')
            input.type = 'file'
            input.style.display = 'none'
            input.addEventListener('change', this.onImportFileChange)
            document.body.appendChild(input)
            this.importInputEl = input
        },
        resetFileInput() {
            if (this.importInputEl) {
                this.importInputEl.value = ''
            }
        },
        tearDownFileInput() {
            if (this.importInputEl) {
                this.importInputEl.removeEventListener('change', this.onImportFileChange)
                if (this.importInputEl.parentNode) {
                    this.importInputEl.parentNode.removeChild(this.importInputEl)
                }
                this.importInputEl = null
            }
        },
        async onImportFileChange(event) {
            const file = event.target.files && event.target.files[0]
            this.resetFileInput()
            if (!file) return

            const config = this.getImportConfig() || {}
            this.importing = true
            this.$emit('import-start', { file })
            try {
                let result
                if (typeof config.request === 'function') {
                    result = await config.request(file, {
                        filters: { ...this.form },
                        pagination: { ...this.pagination },
                        columns: this.columns
                    })
                    config.onSuccess && config.onSuccess({ file, result, from: 'api' })
                    this.$emit('import-success', { file, result, from: 'api' })
                    if (this.$message) {
                        this.$message.success('导入成功')
                    }
                } else {
                    const parsed = await this.parseFileLocally(file, config)
                    config.onVirtualData && config.onVirtualData({ file, data: parsed })
                    config.onSuccess && config.onSuccess({ file, data: parsed, from: 'virtual' })
                    this.$emit('import-virtual-data', { file, data: parsed })
                    if (this.$message) {
                        this.$message.success('导入数据已读取')
                    }
                }
            } catch (error) {
                console.error('SimpleTable 导入失败：', error)
                if (config && typeof config.onError === 'function') {
                    config.onError(error)
                }
                this.$emit('import-error', error)
                if (this.$message) {
                    this.$message.error('导入失败，请稍后重试')
                }
            } finally {
                this.importing = false
                this.$emit('import-finish')
            }
        },
        parseFileLocally(file, config) {
            if (config && typeof config.parse === 'function') {
                return Promise.resolve(config.parse(file))
            }
            return new Promise((resolve, reject) => {
                const reader = new FileReader()
                reader.onload = () => {
                    try {
                        const text = reader.result || ''
                        if (file.name.endsWith('.json')) {
                            resolve(JSON.parse(text))
                            return
                        }
                        if (file.name.endsWith('.csv')) {
                            resolve(this.parseCsv(text))
                            return
                        }
                        resolve(text)
                    } catch (err) {
                        reject(err)
                    }
                }
                reader.onerror = reject
                reader.readAsText(file, 'utf-8')
            })
        },
        parseCsv(content) {
            const lines = (content || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n').filter(line => line.trim())
            if (!lines.length) return []
            const headers = this.splitCsvLine(lines[0])
            return lines.slice(1).map(line => {
                const values = this.splitCsvLine(line)
                const item = {}
                headers.forEach((header, index) => {
                    item[header] = values[index] !== undefined ? values[index] : ''
                })
                return item
            })
        },
        splitCsvLine(line) {
            const result = []
            let current = ''
            let inQuotes = false
            for (let i = 0; i < line.length; i += 1) {
                const char = line[i]
                if (char === '"') {
                    if (inQuotes && line[i + 1] === '"') {
                        current += '"'
                        i += 1
                    } else {
                        inQuotes = !inQuotes
                    }
                } else if (char === ',' && !inQuotes) {
                    result.push(current)
                    current = ''
                } else {
                    current += char
                }
            }
            result.push(current)
            return result.map(item => item.replace(/^"|"$/g, ''))
        },
        resolveExportDataset(sourceData) {
            const config = this.getExportConfig() || {}
            const exportColumns = Array.isArray(config.fields) && config.fields.length
                ? config.fields
                : this.getExportColumns()
            return sourceData.map((row, index) => this.buildExportRow(row, index, exportColumns))
        },
        getExportColumns() {
            return (this.columns || []).filter(column => column && column.type !== 'action')
        },
        buildExportRow(row, index, exportColumns) {
            const record = {}
            exportColumns.forEach((column, columnIndex) => {
                const header = column.exportLabel || column.label || column.prop || `字段${columnIndex + 1}`
                if (column.type === 'index') {
                    const indexMethod = column.indexMethod || this.indexMethod
                    record[header] = indexMethod.call(this, index)
                } else if (typeof column.exportFormatter === 'function') {
                    record[header] = column.exportFormatter(row, column, index)
                } else if (typeof column.formatter === 'function') {
                    record[header] = column.formatter(row, column, index)
                } else if (column.prop) {
                    record[header] = row[column.prop]
                } else {
                    record[header] = this.getCellValue(row, column, index)
                }
            })
            return record
        },
        downloadCsv(rows, filename) {
            if (!rows.length) return
            const headers = Object.keys(rows[0])
            const csvLines = [headers.join(',')]
            rows.forEach(item => {
                const line = headers.map(header => this.escapeCsvValue(item[header]))
                csvLines.push(line.join(','))
            })
            const csvContent = '\ufeff' + csvLines.join('\n')
            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
            this.createBlobAndDownload(blob, filename)
        },
        escapeCsvValue(value) {
            if (value === null || value === undefined) return ''
            const stringValue = value.toString()
            if (/[",\n]/.test(stringValue)) {
                return `"${stringValue.replace(/"/g, '""')}"`
            }
            return stringValue
        },
        createBlobAndDownload(blob, filename) {
            const link = document.createElement('a')
            const url = URL.createObjectURL(blob)
            link.href = url
            link.download = filename || this.resolveExportFilename()
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
            URL.revokeObjectURL(url)
        },
        resolveExportFilename() {
            const date = new Date()
            const pad = value => (value < 10 ? `0${value}` : value)
            const timestamp = `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`
            return `导出数据_${timestamp}.csv`
        },
        getExportConfig() {
            if (!this.exportConfig || typeof this.exportConfig !== 'object') return null
            return this.exportConfig
        },
        getImportConfig() {
            if (!this.importConfig || typeof this.importConfig !== 'object') return null
            return this.importConfig
        }
    },
    beforeDestroy() {
        this.tearDownFileInput()
    }
}
</script>

<style scoped lang="less">
@import "../less/DarkButtonSelect.css";

.simple-table {
    height: 100%;
    width: 100%;

    .header {
        min-height: 50px;
        width: 100%;
        display: flex;
        align-items: center;
        margin-bottom: 12px;
        flex-wrap: wrap;

        .header-form {
            display: flex;
            align-items: center;
            margin: 6px 20px 6px 0;

            span {
                color: #1f2d3d;
                margin-right: 8px;
                white-space: nowrap;
            }

            .el_input,
            .el-select {
                width: 220px;
            }
        }

        .header-buttons {
            display: flex;
            align-items: center;
            margin: 6px 0;

            >div {
                margin-right: 10px;
            }

            .is-disabled {
                opacity: 0.6;
                cursor: not-allowed;
            }
        }
    }

    .content {
        height: calc(100% - 90px);
        width: 100%;

        .el-table {
            width: 100%;
        }

        .page {
            margin-top: 12px;
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }
    }

    .el_input {
        border: 1px solid #e6eeff;
        border-radius: 4px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #296ac2;
        font-weight: 400;
    }

    .blue_btn {
        width: 80px;
        height: 32px;
        background: linear-gradient(90deg, #409eff 0%, #66b3ff 100%);
        border-radius: 4px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #ffffff;
        font-weight: 400;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
    }

    .default_btn {
        width: 80px;
        height: 32px;
        background: #f0f0f0;
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #333333;
        font-weight: 400;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
    }
}
</style>
